#pragma once
#ifndef H_ITEM
#define H_ITEM
#include "precompiled.h"
#include "forwarddecl.h"
namespace weo
{
    namespace engine
    {
        namespace
        {
            static const std::string Slotnames[] = {"Head","Neck","Shoulder","Cloak","Chest","Wrist","Hands","Waist","Legs","Feet","Finger1","Finger2","Trinket1","Trinket2","MainHand","OffHand","Ranged"};
            static const std::string itemType[] = {"None","Armor","Ring","Trinket","Weapon","Gem"};
            static const std::string armorSlot[] = {"None", "Head","Neck","Shoulder","Cloak", "Chest","Wrist","Hands","Waist","Legs","Feet","Shield","OffHand"};
            static const std::string armorType[] = {"Junk", "Cloth", "Leather", "Mail", "Plate", "Shield"};
            static const std::string weaponSlot[] = {"None","OneHand","MainHand","OffHand","TwoHand","Ranged"};
            static const std::string weaponType[] = {"None","Sword","Mace","Axe","FistWeapon","Dagger","Staff","Polearm","FishingPole","Thrown","Crossbow","Bow","Gun","Wand","Feral","Totem","Libram","Idol"};
            static const std::string qualityRating[] = {"Junk","Standard","Good","Rare","Epic","Legendary"};
            static const std::string gemType[] = {"None","Blue","Red","Yellow","Meta"};
            static const std::string itemSource[] = {"None","Drop","Quest","Recipie","Vendor","PVP","Faction","Other"};
            static const std::string profession[] = {"Alchemy","Blacksmithing","Enchanting","Engineering","Herbalism","Jewelcrafting","Leatherworking","Mining","Skinning","Tailoring"};
            static const unsigned int Slotcount = sizeof(Slotnames)/sizeof(std::string);
            static const unsigned int itemTypeLength = sizeof(itemType)/sizeof(std::string);
            static const unsigned int armorSlotLength = sizeof(armorSlot)/sizeof(std::string);
            static const unsigned int armorTypeLength = sizeof(armorType)/sizeof(std::string);
            static const unsigned int weaponSlotLength = sizeof(weaponSlot)/sizeof(std::string);
            static const unsigned int weaponTypeLength = sizeof(weaponType)/sizeof(std::string);
            static const unsigned int qualityRatingLength = sizeof(qualityRating)/sizeof(std::string);
            static const unsigned int gemTypeLength = sizeof(gemType)/sizeof(std::string);
            static const unsigned int itemSourceLength = sizeof(itemSource)/sizeof(std::string);
            static const unsigned int professionLength = sizeof(profession)/sizeof(std::string);
            static const unsigned int GemSlot = Slotcount;
            static const float MobArmor = 7700;
        }
        namespace
        {
            std::map<std::string,unsigned int> AttributeMap;
            std::map<std::string,unsigned int> ItemsourceMap;
            std::map<std::string,unsigned int> ProfessionMap;
            std::map<std::string,unsigned char> ColorMap;			
            std::map<std::string,unsigned char> QualityMap;
            void InitItem();
        }
        namespace item
        {
            typedef const weo::engine::item::Item* ItemPtr;
            typedef const weo::engine::item::Item* GemPtr;
            static const float ExpertiseRating = 3.9f;
            static const float HitRating = 15.8f;
            static const float HitSpellRating = 12.6f;
            static const float CritRating = 22.1f;
            static const float HasteRating = 15.76f; //10.5f;
            static const float HasteSpellRating = 15.76f; //21f;
            static const float CritSpellRating = 22.1f;
            static const float DefenseRating = 2.4f;
            static const float DodgeRating = 18.9f;
            static const float ParryRating = 22.4f;
            static const float BlockRating = 7.9f;
            static const std::string KeyValues[] = 
            {"None", "Agility",  "Intellect", "Strength", "Stamina", "Spirit", "CritRating", "HitRating", "CritMeleeRating", "HitMeleeRating", "HasteRating", "HitSpellRating", 
            "CritSpellRating", "HasteSpellRating", "DodgeRating", "ParryRating", "BlockRating", "BlockValue", "DefenseRating", "ResilienceRating",
            "Healing", "MP5", "HP5", "SpellDamage", "FireSpellDamage", "ArcaneSpellDamage", "FrostSpellDamage", "NatureSpellDamage", "HolySpellDamage", "ShadowSpellDamage",
            "AttackPower", "RangedAttackPower", "SpellPenetration", "Armor", "Health", "Mana", "WeaponSkill", "FeralAP", "HasteDirect", "ShadowResist", "NatureResist",
            "FrostResist", "FireResist", "ArcaneResist", "ResistAll", "Special", "MainhandDps", "MainhandSpeed","OffhandDps", "OffhandSpeed", "ArmorPenetration", "ExpertiseRating"};
            static const unsigned int KeyValuesLength = sizeof(KeyValues)/sizeof(std::string);
            class Attribute : public gc
            {
            private:
                int m_Type;
                float m_Value;
                friend class boost::serialization::access;
                template<class Archive>
                void serialize(Archive & ar, const unsigned int /* file_version */)
                {
                    ar & boost::serialization::make_nvp("Type",m_Type);
                    ar & boost::serialization::make_nvp("Value",m_Value);
                };
            public:
                Attribute();
                Attribute(const std::string type, const float value);
                Attribute(const unsigned int type, const float value);
                int Type() const {return m_Type;};
                float Value() const {return m_Value;};
                void setType(const int value) {m_Type = value;};
                void setValue(const float value) {m_Value = value;};
                friend std::size_t hash_value(Attribute const &attr)
                {
                    std::size_t seed = 0;
                    boost::hash_combine(seed, attr.m_Type);
                    boost::hash_combine(seed, attr.m_Value);
                    return seed;
                }
                static unsigned int getAttributeValue(const std::string& value);
                bool toXmlElement(ticpp::Element * child) const;
                bool fromXmlElement(const ticpp::Element * child);
            };
            class Sockets : public gc
            {
            private:
                unsigned char m_Count;
                std::vector<Attribute> m_Bonus;
                std::vector<unsigned char> m_Colors;
                friend class boost::serialization::access;
                template<class Archive>
                void serialize(Archive & ar, const unsigned int /* file_version */)
                {
                    ar & boost::serialization::make_nvp("Socketcount",m_Count);
                    ar & boost::serialization::make_nvp("Bonus",m_Bonus);
                    ar & boost::serialization::make_nvp("Socketcolors",m_Colors);
                };
            public:
                Sockets();
                unsigned char Count() const {return m_Count;};
                void setCount(const unsigned int value) {m_Count = value;};
                const std::vector<unsigned char>* Colors() const {return &m_Colors;};
                void setColors(const std::vector<unsigned char>& value) 
                {
                    m_Colors.assign(value.begin(),value.end());
                };
                const std::vector<Attribute>* Bonus() const {return &m_Bonus;};
                void setBonus(const std::vector<Attribute> & value) {
                    m_Bonus.assign(value.begin(),value.end());
                };
                Sockets& operator=(const Sockets& sockets);
                static unsigned char GetColor(const std::string& value);
                bool toXmlElement(ticpp::Element * root) const;
                bool fromXmlElement(const ticpp::Element * child);
            };
            class Set : public gc
            {
            private:
                std::string m_Name;
                std::vector<std::string> m_Item;
                std::vector<std::pair<unsigned char,Attribute>> m_Bonus;
                size_t m_Hash;
                friend class boost::serialization::access;
                template<class Archive>
                void serialize(Archive & ar, const unsigned int /* file_version */)
                {
                    ar & boost::serialization::make_nvp("Name",m_Name);
                    ar & boost::serialization::make_nvp("Bonus",m_Bonus);
                    ar & boost::serialization::make_nvp("Item",m_Item);
                    ar & boost::serialization::make_nvp("SetHash",m_Hash);
                };
            public:
                std::string Name() const {return m_Name;};
                size_t Hash() const {return m_Hash;};
                void setHash(size_t value) {m_Hash = value;};
                void setName(const std::string value) {m_Name = value;};
                const std::vector<std::pair<unsigned char,Attribute>>* Bonus() const {return & m_Bonus;};
                void setBonus(const std::vector<std::pair<unsigned char,Attribute>> & value) {
                    m_Bonus.assign(value.begin(),value.end());
                };
                const std::vector<std::string>* Item() const {return &m_Item;};
                void setItem(const std::vector<std::string> & value) {
                    m_Item.assign(value.begin(),value.end());
                };
                Set& operator=(const Set& set);
                Set();
                bool toXmlElement(ticpp::Element * root) const;
                bool fromXmlElement(const ticpp::Element * child);
            };
            // Type: Armor = 1, Ring = 2, Trinket = 3, Weapon = 4, Gem = 5
            class Item : public gc
            {
            private:
                static Item* s_None;
            protected:
                unsigned int m_Id;
                std::string m_Name;
                std::string m_Icon;
                unsigned int m_Level;
                bool m_Unique;
                unsigned char m_Type;
                unsigned char m_Subtype;
                unsigned char m_Slot;
                unsigned int m_Itemsource;
                unsigned int m_Profession;
                unsigned char m_Quality;
                float m_Speed;
                float m_DPS;
                unsigned int m_Allowed;
                std::vector<Attribute> m_Attributes;
                Set m_Set;
                Sockets m_Sockets;
                std::vector<std::string> m_Areaname;
                std::vector<std::string> m_Creaturename;
                friend class boost::serialization::access;
                template<class Archive>
                void serialize(Archive & ar, const unsigned int /* file_version */)
                {
                    ar & boost::serialization::make_nvp("Quality",m_Quality);
                    ar & boost::serialization::make_nvp("Id",m_Id);
                    ar & boost::serialization::make_nvp("Name",m_Name);
                    ar & boost::serialization::make_nvp("Icon",m_Icon);
                    ar & boost::serialization::make_nvp("Level",m_Level);
                    ar & boost::serialization::make_nvp("Unique",m_Unique);
                    ar & boost::serialization::make_nvp("Type",m_Type);
                    ar & boost::serialization::make_nvp("Subtype",m_Subtype);
                    ar & boost::serialization::make_nvp("Slot",m_Slot);
                    ar & boost::serialization::make_nvp("Speed",m_Speed);
                    ar & boost::serialization::make_nvp("DPS",m_DPS);
                    ar & boost::serialization::make_nvp("Attributes",m_Attributes);
                    ar & boost::serialization::make_nvp("Allowed",m_Allowed);
                    ar & boost::serialization::make_nvp("Socket",m_Sockets);
                    ar & boost::serialization::make_nvp("Set",m_Set);
                    ar & boost::serialization::make_nvp("Itemsource",m_Itemsource);
                    ar & boost::serialization::make_nvp("Profession",m_Profession);
                    ar & boost::serialization::make_nvp("Areaname",m_Areaname);
                    ar & boost::serialization::make_nvp("Creaturename",m_Creaturename);
                };
            public:
                const std::size_t Hash() const {return m_Id;};
                unsigned char Quality() const{return m_Quality;};
                void setQuality(const unsigned char value) {m_Quality = value;};
                void setQuality(const std::string value);
                static unsigned char GetQuality(const std::string value);
                unsigned int Itemsource() const{return m_Itemsource;};
                void setItemsource(const unsigned int value) {m_Itemsource = value;};
                void setItemsource(const std::string value);
                static unsigned int GetItemsource(const std::string value);
                void setProfession(const unsigned int value) {m_Profession = value;};
                void setProfession(const std::string value);
                unsigned int Profession() const {return m_Profession;};
                static unsigned int GetProfession(const std::string value);
                unsigned int Id() const{return m_Id;};
                void setId(const unsigned int value) {m_Id = value;};
                std::string Name() const{return m_Name;};
                void setName(const std::string value) {m_Name = value;};
                std::string Icon() const{return m_Icon;};
                void setIcon(const std::string value) {m_Icon = value;};
                unsigned int Level() const{return m_Level;};
                void setLevel(const unsigned int value) {m_Level = value;};
                bool Unique() const{return m_Unique;};
                void setUnique(const bool value) {m_Unique = value;};
                unsigned char Type() const {return m_Type;};
                void setType(const unsigned char value) {m_Type = value;};
                unsigned char Subtype() const {return m_Subtype;};
                void setSubtype(const unsigned char value) {m_Subtype = value;};
                unsigned char Slot() const {return m_Slot;};
                void setSlot(const unsigned char value) {m_Slot = value;};
                unsigned int Allowed() const {return  m_Allowed;};
                void setAllowed(const unsigned int value) { m_Allowed = value;};
                float Speed() const {return m_Speed;};
                void setSpeed(const float value) {m_Speed = value;};
                float DPS() const {return m_DPS;};
                void setDPS(const float value) {m_DPS = value;};
                const std::vector<Attribute>* Attributes() const {return &m_Attributes;};
                void setAttributes(const std::vector<Attribute> & value) {
                    m_Attributes.assign(value.begin(),value.end());
                };
                const weo::engine::item::Sockets* Sockets() const {return &m_Sockets;};
                void setSockets(const weo::engine::item::Sockets& value) {m_Sockets = value;};
                const weo::engine::item::Set* Set() const {return &m_Set;};
                void setSet(const weo::engine::item::Set& value) {m_Set = value;};
                const std::vector<std::string>* Areaname() const {return &m_Areaname;};
                void setAreaname(const std::string value);
                const std::vector<std::string>* Creaturename() const {return &m_Creaturename;};
                void setCreaturename(const std::string value);
                static std::vector<std::string> GetItemSources();
                static std::vector<std::string> GetProfessions();
                static std::vector<std::string> GetQualities();
                Item();
                Item(const std::string &name, const int &id);
                Item& operator=(const Item& item);
                bool operator==(const Item& other);
                bool operator<(const Item& other);
                void AddAttribute(Attribute const& value);
                static Item* None();
                friend std::size_t hash_value(Item& x)
                {
                    return x.Hash();
                }
                bool toXmlElement(ticpp::Element* root) const;
                bool fromXmlElement(const ticpp::Element* root);
                const unsigned int matchString(const std::string* inputArray,const unsigned int length, const std::string value) const
                {                    
                    std::string checkValue = boost::algorithm::to_lower_copy(value);
                    for(unsigned int i = 0;i<length;i++)
                    {
                        std::string cmpValue = boost::algorithm::to_lower_copy(inputArray[i]);
                        if(cmpValue == checkValue)
                        {
                            return i;
                        }
                    }
                    return 0;
                }
                static bool CheckMetaGemRequirements(const weo::engine::item::GemPtr* gems);
            };
        };
    };
};
#endif